from Config.myConstant import *
from Config.myConfig import *
from DataPrepare.tickFactorsLongTerm.factorBase import factorBase
from DataAccess.TickDataProcess import TickDataProcess
import pandas as pd
import numpy as np
import math
########################################################################
class midPricediffChange2(factorBase):
    """描述盘口状态的因子"""
    #----------------------------------------------------------------------
    def __init__(self):
        #super(buySellVolumeRatio,self).__init__()
        super().__init__()
        self.factor='midPriceChange'
        pass
    #----------------------------------------------------------------------
    def getFactorFromLocalFile(self,code,date):
        mydata=super().getFromLocalFile(code,date,'midPriceChange')
        return mydata
        pass
    #----------------------------------------------------------------------
    def updateFactor(self,code,date,data=pd.DataFrame()):
        exists=super().checkLocalFile(code,date,self.factor)
        if exists==True:
            logger.info(f'No need to compute! {self.factor} of {code} in {date} exists!')
            pass
        if data.shape[0]==0:
             #data=TickDataProcess().getDataByDateFromLocalFile(code,date)
             data=TickDataProcess().getTickShotDataFromInfluxdbServer(code,date)
        result=self.computerFactor(code,date,data)
        super().updateFactor(code,date,self.factor,result)
    #----------------------------------------------------------------------
    def __computeVwap(self,data,n):
        result=data[['midPrice','amount','volume']].copy()
        colname='vwap'+str(n)+'ticks'
        result[colname]= (result['amount']-result['amount'].shift(n))/(result['volume']-result['volume'].shift(n))
        select=result.index[0:n]
        result.loc[select,colname]=(result['amount']-result['amount'].iloc[0])/(result['volume']-result['volume'].iloc[0])[select]
        result[colname]=result[colname].replace(np.inf,np.nan)
        result[colname]=result[colname].replace(-np.inf,np.nan)
        select=result[colname].isna()==True
        result.loc[select,colname]=result['midPrice'][select]
        #data[colname]=result[colname]
        return result[colname]
        pass
    #----------------------------------------------------------------------
    def __distanceBetweenTwoColumns(self,data,col1,col2):
        result=data[[col1,col2]].copy()
        select=data[col1]!=0
        result['distance']=0
        result.loc[select,'distance']=(1000*(data[col1]-data[col2])/data[col1])[select]
        return result['distance']
        pass
    #----------------------------------------------------------------------
    def __midSpeed(self,data,span,period):
        result=data[['tick','midPrice']].copy()
        result['EMAMidPrice']=super().EMA(data['midPrice'],span)
        result['speed']=100*np.round((result['EMAMidPrice']/result['EMAMidPrice'].shift(period)-1),5)/(period/20)
        select=result['speed'].isna()
        result.loc[select,'speed']=0
        return result['speed']
        pass
    #----------------------------------------------------------------------
    def __midMomentum(self,data,span,period):
        result=data[['midPrice','amount']].copy()
        result['EMAMidPrice']=super().EMA(data['midPrice'],span)
        result['speed']=100*np.round((result['EMAMidPrice']/result['EMAMidPrice'].shift(period)-1),5)/(period/20)
        result.loc[result['speed'].isna(),'speed']=0
        result['amountPeriodIncrease']=result['amount'].rolling(period,min_periods=1).apply((lambda x:x[-1]-x[0]))
        result['momentum']=0
        select=result['speed']>0
        result.loc[select,'momentum']=np.log(np.abs(result['speed']*result['amountPeriodIncrease'])+0.001)[select]
        select=result['speed']<0
        result.loc[select,'momentum']=-np.log(np.abs(result['speed']*result['amountPeriodIncrease'])+0.001)[select]
        return result['momentum']
        pass
    #----------------------------------------------------------------------
    #vwap15s的部分计算-夏普率
    def sharpe(self,x,interval,period):
        y=x[::-interval]
        z=y[::-1]
        r=z[1:]/z[0:-1]-1
        r=r[-period:]
        if (len(r)>1) and (np.mean(r)!=0):
            sharpeRatio=np.mean(r)/np.std(r)
        else:
            sharpeRatio=0
        return sharpeRatio
    #----------------------------------------------------------------------
    #vwap15s的部分计算-分位数
    def quantile(self,x,interval,period):
        y=x[::-interval]
        z=y[::-1]
        w=z/z[0]-1
        w=w[1:]
        w=w[-period:]
        u=z[z>z[-1]]
        totalnum=len(z)
        biggernum=len(u)
        myquantile=1-(biggernum+1)/(totalnum+1)
        return myquantile
    def __midPricediff(self,data,span,period):
        result=data[['tick','midPrice']].copy()
        result['diff1'] = 100 * np.round((result['midPrice'] / result['midPrice'].shift(period) - 1), 5) / (period / 20)
        select=result['diff1'].isna()
        result.loc[select,'diff1']=0
        result['midPricediff1'] = super().EMA(result['diff1'], span)
        select = result['midPricediff1'].isna()
        result.loc[select, 'midPricediff1'] = 0
        return result['midPricediff1']

        pass

    def __midPriceSquarediff(self,data,span,period):
        result=data[['tick','midPrice']].copy()
        result['diffsquare1'] = 100 * np.round((result['midPrice']*result['midPrice'] / result['midPrice'].shift(period)*result['midPrice'].shift(period) - 1), 5) / (period / 20)
        select=result['diffsquare1'].isna()
        result.loc[select,'diffsquare1']=0
        result['midPricediffdiffsquare1'] = super().EMA(result['diffsquare1'], span)
        select = result['midPricediffdiffsquare1'].isna()
        result.loc[select, 'midPricediffdiffsquare1'] = 0
        return result['midPricediffdiffsquare1']

        pass
    #----------------------------------------------------------------------
    def __midPricediff2(self,data,span,period):
        result=data[['tick','midPrice']].copy()
        result['diff2'] = 100 * np.round((result['midPrice']-result['midPrice'].shift(1)-result['midPrice'].shift(period)+result['midPrice'].shift(period+1) / result['midPrice'].shift(period+1) - 1), 5) / (period / 20)
        select=result['diff2'].isna()
        result.loc[select,'diff2']=0
        result['midPricediff2'] = super().EMA(result['diff2'], span)
        select = result['midPricediff2'].isna()
        result.loc[select, 'midPricediff2'] = 0
        return result['midPricediff2']
        pass
    #----------------------------------------------------------------------
    def __midPrice_weightdiff(self,data,span,period):
        result=data[['tick','midPrice']].copy()
        result['weightdiff'] = 10000 * np.round((result['midPrice'] / result['midPrice'].shift(1) - 1)*((result['midPrice'].shift(1) / result['midPrice'].shift(2) - 1) ** 0.3), 5) / (period / 20)

        select=result['weightdiff'].isna()
        result.loc[select,'weightdiff']=0
        result['__midPrice_weightdiff'] = super().EMA( result['weightdiff'], span)
        select = result['__midPrice_weightdiff'].isna()
        result.loc[select, '__midPrice_weightdiff'] = 0
        return result['__midPrice_weightdiff']

        pass
    #----------------------------------------------------------------------
    def computerFactor(self,code,date,mydata):
        result=pd.DataFrame()
        if mydata.shape[0]!=0:
            result=mydata[['midPrice','amount','volume','tick','amountIncrease']].copy()
            result['midPrice'].fillna(method='ffill',inplace=True)
            #----------------------------------------------------------------------
            #计算不同周期的vwap价格,基础因子
            result['vwap15s']=self.__computeVwap(result,5)
            result['vwap1m']=self.__computeVwap(result,20)
            result['vwap2m']=self.__computeVwap(result,40)
            result['vwap5m']=self.__computeVwap(result,100)
            result['vwap10m']=self.__computeVwap(result,200)
            result['vwap30m']=self.__computeVwap(result,600)

            #myindex={}
            #columnsNames=list(result.columns)
            #for item in result.columns:
            #    myindex.update({item:columnsNames.index(item)})
            #resultArr=result.values
            #length=resultArr.shape[0]
            #arr=np.zeros([length,1])
            #for k in range(length):
            #    amountIncrease=resultArr[k,myindex['amount']]-resultArr[max(k-5,0),myindex['amount']]
            #    volumeIncrease=resultArr[k,myindex['volume']]-resultArr[max(k-5,0),myindex['volume']]
            #    midPrice=resultArr[k,myindex['midPrice']]
            #    if (volumeIncrease>0):
            #        arr[k,0]=amountIncrease/volumeIncrease
            #    else:
            #        arr[k,0]=midPrice
            #    pass
            #result['vwap15sCheck']=arr[:,0]

            #print(result[result['vwap15sCheck']!=result['vwap15s']])

            #----------------------------------------------------------------------
            #去掉第一条集合竞价的数据
            result=result.iloc[1:]

            #----------------------------------------------------------------------
            #计算今日开盘以来的vwap价格
            result['vwapToday']=result['amount']/result['volume']
            #如果vwap价格不存在，使用midPrice来代替
            select=result['vwapToday'].isna()==True
            result.loc[select,'vwapToday']=result['midPrice'][select]
            #计算vwap15s到vwap价格的距离，大多数落在±10%
            result['vwap15sToVwap']=(result['vwap15s']-result['vwapToday'])/result['vwapToday']
            result['vwap15sTo1m']=(result['vwap15s']-result['vwap1m'])/result['vwap1m']
            result['vwap15sTo2m']=(result['vwap15s']-result['vwap2m'])/result['vwap2m']
            result['vwap15sTo5m']=(result['vwap15s']-result['vwap5m'])/result['vwap5m']
            result['vwap15sTo10m']=(result['vwap15s']-result['vwap10m'])/result['vwap10m']
            result['vwap15sTo30m']=(result['vwap15s']-result['vwap30m'])/result['vwap30m']

            result['midPricediff_5_3'] = self.__midPricediff(result, 5, 3)
            result['midPricediff_50_3'] = self.__midPricediff(result, 50, 3)
            result['midPricediff_5_10'] = self.__midPricediff(result, 5, 10)
            result['midPricediff_3_50'] = self.__midPricediff(result, 3, 50)

            result['midPriceSquardiff_5_3'] = self.__midPriceSquarediff(result, 5, 3)
            result['midPriceSquardiff_50_3'] = self.__midPriceSquarediff(result, 50, 3)
            result['midPriceSquardiff_5_10'] = self.__midPriceSquarediff(result, 5, 10)
            result['midPriceSquardiff_3_50'] = self.__midPriceSquarediff(result, 3, 50)

            result['midPricediff_weight_5_3'] = self.__midPrice_weightdiff(result, 5, 3)
            result['midPricediff_weight_50_3'] = self.__midPrice_weightdiff(result, 50, 3)
            result['midPricediff_weight_5_10'] = self.__midPrice_weightdiff(result, 5, 10)
            result['midPricediff_weight_3_50'] = self.__midPrice_weightdiff(result, 3, 50)

            openPrice = mydata['lastPrice'].iloc[0]
            if (openPrice == 0):
                openPrice = mydata['midPrice'].iloc[0]

            result['midPriceinter'] = (result['midPrice'] - openPrice) / openPrice
            result['midPrice_intergral_abs60'] = result['midPriceinter'].rolling(60, min_periods=1).apply(lambda x: np.sum(np.abs(x)))
            result['midPrice_intergral_abs30'] = result['midPriceinter'].rolling(30, min_periods=1).apply(lambda x: np.sum(np.abs(x)))
            result['midPrice_intergral_abs5'] = result['midPriceinter'].rolling(5, min_periods=1).apply(lambda x: np.sum(np.abs(x)))
            result['midPrice_intergral_abs120'] = result['midPriceinter'].rolling(120, min_periods=1).apply(lambda x: np.sum(np.abs(x)))
            result['midPrice_intergral_abs360'] = result['midPriceinter'].rolling(360, min_periods=1).apply(lambda x: np.sum(np.abs(x)))

            result['midPrice_intergral_60'] = result['midPriceinter'].rolling(60, min_periods=1).apply(lambda x: np.sum(x))
            result['midPrice_intergral_30'] = result['midPriceinter'].rolling(30, min_periods=1).apply(lambda x: np.sum(x))
            result['midPrice_intergral_5'] = result['midPriceinter'].rolling(5, min_periods=1).apply(lambda x: np.sum(x))
            result['midPrice_intergral_120'] = result['midPriceinter'].rolling(120, min_periods=1).apply( lambda x: np.sum(x))
            result['midPrice_intergral_360'] = result['midPriceinter'].rolling(360, min_periods=1).apply(lambda x: np.sum(x))

            #----------------------------------------------------------------------
            #计算vwap15s价格的涨跌
            #result['vwap15sPriceIncrease']=(result['vwap15s']-result['vwap15s'].shift(5))/result['vwap15s'].shift(5)
            #select=result['vwap15sPriceIncrease'].isna()==True
            #result.loc[select,'vwap15sPriceIncrease']=0
            result['vwap15sPriceIncrease']=result['vwap15s'].rolling(5,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)
            
            result['vwap15sPriceIncreasePrevious1m']=result['vwap15s'].rolling(20,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)
            result['vwap15sPriceIncreasePrevious2m']=result['vwap15s'].rolling(40,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)
            result['vwap15sPriceIncreasePrevious5m']=result['vwap15s'].rolling(100,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)
            result['vwap15sPriceIncreasePrevious10m']=result['vwap15s'].rolling(200,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)
            result['vwap15sPriceIncreasePrevious30m']=result['vwap15s'].rolling(600,min_periods=1).apply(lambda x:x[-1]/x[0]-1,raw=True)


            #myindex={}
            #columnsNames=list(result.columns)
            #for item in result.columns:
            #    myindex.update({item:columnsNames.index(item)})
            #resultArr=result.values
            #length=resultArr.shape[0]
            #arr=np.zeros([length,2])
            #for k in range(length):
            #    vwap15s=resultArr[k,myindex['vwap15s']]
            #    vwap15s5ticksBefore=resultArr[max(k-5,0),myindex['vwap15s']]
            #    vwap15s30mBefore=resultArr[max(k-600,0),myindex['vwap15s']]
            #    vwap15sPriceIncrease=(vwap15s-vwap15s5ticksBefore)/vwap15s
            #    vwap15sPriceIncreasePrevious30m=(vwap15s-vwap15s30mBefore)/vwap15s
            #    arr[k,0]=vwap15sPriceIncrease
            #    arr[k,1]=vwap15sPriceIncreasePrevious30m
            #    pass
            #result['vwap15sPriceIncreaseCheck']=arr[:,0]
            #result['vwap15sPriceIncreasePrevious30mCheck']=arr[:,1]


            #print(result[abs(result['vwap15sPriceIncreaseCheck']-result['vwap15sPriceIncrease'])>0.0001])
            #print(result[result['vwap15sPriceIncreasePrevious30mCheck']!=result['vwap15sPriceIncreasePrevious30m']])


            #----------------------------------------------------------------------
            #计算vwap15s价格的夏普率和分位数
            result['vwap15sSharpe2m']=result['vwap15s'].rolling(40,min_periods=1).apply(self.sharpe,args=(5,8),raw=True)
            result['vwap15sSharpe5m']=result['vwap15s'].rolling(100,min_periods=1).apply(self.sharpe,args=(5,20),raw=True)
            result['vwap15sSharpe10m']=result['vwap15s'].rolling(200,min_periods=1).apply(self.sharpe,args=(5,40),raw=True)
            result['vwap15sSharpe30m']=result['vwap15s'].rolling(600,min_periods=1).apply(self.sharpe,args=(5,120),raw=True)

            result['vwap15sQuantile2m']=result['vwap15s'].rolling(40,min_periods=1).apply(self.quantile,args=(5,8),raw=True)
            result['vwap15sQuantile5m']=result['vwap15s'].rolling(100,min_periods=1).apply(self.quantile,args=(5,20),raw=True)
            result['vwap15sQuantile10m']=result['vwap15s'].rolling(200,min_periods=1).apply(self.quantile,args=(5,40),raw=True)
            result['vwap15sQuantile30m']=result['vwap15s'].rolling(600,min_periods=1).apply(self.quantile,args=(5,120),raw=True)




            #myindex={}
            #columnsNames=list(result.columns)
            #for item in result.columns:
            #    myindex.update({item:columnsNames.index(item)})
            #resultArr=result.values
            #length=resultArr.shape[0]
            #arr=np.zeros([length,2])
            #for k in range(length):
            #    mylist=[]
            #    vwap15s=resultArr[k,myindex['vwap15s']]
            #    #h=resultArr[k,myindex['vwap15sSharpe2m']]
            #    biggernum=0
            #    for i in range(120):
            #        index=k-i*5
            #        if (index>=0):
            #            if (resultArr[index,myindex['vwap15s']]>vwap15s):
            #                biggernum+=1
            #            mylist.append(resultArr[index,myindex['vwap15s']])
            #    mylist=np.array(mylist)
            #    r=mylist[0:-1]/mylist[1:]-1
            #    if (len(r)<=1):
            #        sharpe=0
            #    else:
            #        sharpe=np.mean(r)/np.std(r)
            #    totalnum=len(mylist)
            #    myquantile=1-(biggernum+1)/(totalnum+1)
            #    #print(f"sharpe1 {h} sharpe2 {sharpe}")
            #    arr[k,0]=sharpe
            #    arr[k,1]=myquantile
            #    pass
            #result['vwap15sSharpe30mCheck']=arr[:,0]
            #result['vwap15sQuantile30mCheck']=arr[:,1]


            #print(result[abs(result['vwap15sSharpe30mCheck']-result['vwap15sSharpe30m'])>0.0001])
            #print(result[result['vwap15sQuantile30mCheck']!=result['vwap15sQuantile30m']])




            #计算vwap15s的10m/30m有界变差,大多数落在[0,1]之间
            result['vwap15sBV10m']=result['vwap15sPriceIncrease'].rolling(200,min_periods=1).apply(lambda x:np.sum(np.abs(x[::-5])),raw=True)
            result['vwap15sToBV10m']=result['vwap15sPriceIncreasePrevious10m']/result['vwap15sBV10m']
            select=result['vwap15sBV10m']==0
            #result['vwap15sToBV10m']=result['vwap15sToBV10m'].replace(np.inf, np.nan)
            #select=result['vwap15sToBV10m'].isna()==True
            result.loc[select,'vwap15sToBV10m']=0
            
            result['vwap15sBV30m']=result['vwap15sPriceIncrease'].rolling(600,min_periods=1).apply(lambda x:np.sum(np.abs(x[::-5])),raw=True)
            result['vwap15sToBV30m']=result['vwap15sPriceIncreasePrevious30m']/result['vwap15sBV30m']
            select=result['vwap15sBV30m']==0
            #result['vwap15sToBV30m']=result['vwap15sToBV30m'].replace(np.inf, np.nan)
            #select=result['vwap15sToBV30m'].isna()==True
            result.loc[select,'vwap15sToBV30m']=0
            

            #----------------------------------------------------------------------
            #前推10/30分钟的最大最小值之差
            result['maxVwap15sPrice10m']=result['vwap15s'].rolling(200,min_periods=1).max()
            result['minVwap15sPrice10m']=result['vwap15s'].rolling(200,min_periods=1).min()
            result['differenceHighLow10m']=(result['maxVwap15sPrice10m']-result['minVwap15sPrice10m'])/result['vwap15s']
            result['vwap15sInPrevious10m']=(result['maxVwap15sPrice10m']-result['vwap15s'])/(result['maxVwap15sPrice10m']-result['minVwap15sPrice10m'])
            select=result['maxVwap15sPrice10m']==result['minVwap15sPrice10m']
            result.loc[select,'vwap15sInPrevious10m']=0.5
            
            result['maxVwap15sPrice30m']=result['vwap15s'].rolling(600,min_periods=1).max()
            result['minVwap15sPrice30m']=result['vwap15s'].rolling(600,min_periods=1).min()
            result['differenceHighLow30m']=(result['maxVwap15sPrice30m']-result['minVwap15sPrice30m'])/result['vwap15s']
            result['vwap15sInPrevious30m']=(result['maxVwap15sPrice30m']-result['vwap15s'])/(result['maxVwap15sPrice30m']-result['minVwap15sPrice30m'])
            select=result['maxVwap15sPrice30m']==result['minVwap15sPrice30m']
            result.loc[select,'vwap15sInPrevious30m']=0.5

            #前推前10m/30m vwap15s的波动率
            result['vwap15sStd10m']=result['vwap15sPriceIncrease'].rolling(200,min_periods=1).apply(lambda x:np.std(x[::-5]),raw=True)
            result['vwap15sStd10m'].fillna(method='ffill',inplace=True)
            select=result['vwap15sStd10m'].isna()==True
            result.loc[select,'vwap15sStd10m']=0

            result['vwap15sStd30m']=result['vwap15sPriceIncrease'].rolling(600,min_periods=1).apply(lambda x:np.std(x[::-5]),raw=True)
            result['vwap15sStd30m'].fillna(method='ffill',inplace=True)
            select=result['vwap15sStd30m'].isna()==True
            result.loc[select,'vwap15sStd30m']=0


            #计算vwap15s的在vwap10/30m±2std的位置
            result['vwap15sInPrevious10mByStd']=(result['vwap15s']-result['vwap10m'])/(result['vwap10m']*(2*result['vwap15sStd10m']))
            select=result['vwap15sStd10m']==0
            result.loc[select,'vwap15sInPrevious10mByStd']=0
            result['vwap15sInPrevious30mByStd']=(result['vwap15s']-result['vwap30m'])/(result['vwap30m']*(2*result['vwap15sStd30m']))
            select=result['vwap15sStd30m']==0
            result.loc[select,'vwap15sInPrevious30mByStd']=0
            #计算vwap15s和dailyPreclose，openPrice之间的关系
            preClose=mydata['dailyPreClose'].iloc[0]
            openPrice=mydata['lastPrice'].iloc[0]
            if (openPrice==0):
                openPrice=mydata['midPrice'].iloc[0]
            result['vwap15sIncreaseToOpen']=(result['vwap15s']-openPrice)/openPrice
            result['vwap15sIncreaseToPreClose']=(result['vwap15s']-preClose)/preClose
            result['openToPreClose']=(openPrice-preClose)/preClose
            result['vwap15sInOpenAndClose']=(result['vwap15s']-openPrice)/(openPrice-preClose+0.001)



            #------------------------------------------------------------------
            #剔除14点57分之后，集合竞价的数据
            result = result.replace(-np.inf, np.nan)
            result = result.replace(np.inf, np.nan)
            result=result[result['tick']<'144700000']
            mycolumns=list(set(result.columns).difference(set(mydata.columns)))
            mycolumns.sort()
            result=result[mycolumns]
            super().checkDataNan(code,date,self.factor,result)
        else:
            logger.error(f'There no data of {code} in {date} to computer factor!') 
        return result
    
########################################################################
